<template>
  <div v-loading="loading" class="container">
    <el-form ref="form" :inline="true" label-position="left" size="mini">
      <el-form-item label="实例:">
        <el-select
          v-model="dbSelectCondition"
          style="min-width: 260px"
          clearable
          filterable
          placeholder="请选择实例"
        >
          <el-option
            v-for="item in dbSelecteds"
            :key="item.id"
            :label="item.tags + '|' + item.host"
            :value="item.id"
          />
        </el-select>
      </el-form-item>

      <el-form-item label="时间选择:">
        <div style="align-items: center">
          <el-date-picker
            v-model="dateSelectCondition"
            style="width: 160px"
            type="date"
            value-format="yyyy-MM-dd"
            placeholder="选择日期"
            @change="selecteTime"
          />
          <el-time-picker
            v-model="timeSelectCondition"
            style="margin-left: 5px"
            is-range
            format="HH:mm"
            value-format="HH:mm"
            range-separator="至"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            placeholder="选择时间范围"
            @change="selecteTime"
          />
        </div>

      </el-form-item>

    </el-form>

    <div style="display: flex; flex-direction: row; width: 100%; height: 400px;">
      <el-card shadow="always" style="width: 70%; margin-right: 25px">

        <div style="display: flex; flex-direction: row; width: 100%; align-items: center; justify-content: space-between; flex-wrap: wrap">
          <div class="card-header-title" style="display: flex; flex-direction: row; align-items: center; flex-wrap: wrap">SQL统计
            <span><div style="color: #999999; font-size: 12px; margin-left: 10px">(可框选该图表与其它图表联动)</div></span></div>
          <div style="color: #999999; font-size: 12px;"> 所选时间：{{ sqlQueryCoordRangeStart }} ~ {{ sqlQueryCoordRangeEnd }}</div>
        </div>

        <el-divider />
        <VChart ref="sqlQueryChart" class="sqlQueryChart" :option="sqlQueryChartOption" autoresize @brushEnd="brushEnd" />
      </el-card>

      <el-card shadow="always" style="width: 30%;">
        <div class="card-header-title">分段耗时SQL分布</div>
        <el-divider />
        <VChart class="sqlSlowQueryChart" :option="sqlSlowQueryChartOption" autoresize />
      </el-card>
    </div>

    <el-card shadow="always" style="margin-top: 20px;">
      <el-table
        :data="tableData"
        border
        header-align="center"
        style="min-width: 300px; margin-bottom: 20px"
        size="mini"
      >
        <el-table-column prop="query" fixed="left" min-width="200" label="SQL语句" align="center">
          <template slot-scope="scope">
            <el-popover trigger="hover" placement="top">
              <div>{{ scope.row.query }}</div>
              <div slot="reference" class="name-wrapper">
                <div>{{ scope.row.query | sqlFilter }}</div>
              </div>
            </el-popover>
          </template>
        </el-table-column>
        <el-table-column prop="db" min-width="90" label="数据库名称" align="center" />
        <el-table-column prop="user" min-width="90" label="用户" align="center" />
        <el-table-column prop="duration" sortable min-width="150" label="持续时间（毫秒）" align="center">
          <template slot-scope="scope">
            {{ stringFoFixed2(scope.row.duration) }}
          </template>
        </el-table-column>
        <el-table-column prop="start_at" sortable min-width="150" label="请求时间" align="center" />
        <el-table-column prop="client" sortable min-width="160" label="请求地址" align="center" />
        <el-table-column label="优化" align="center" fixed="right" min-width="160">
          <template slot-scope="scope">
            <el-button size="mini" type="primary" @click="analyse(scope.row)">优化
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        class="pagination"
        background=""
        layout="prev, pager, next"
        :current-page="pageIndex"
        :page-size="pageSize"
        :total="totalItems"
        @current-change="curPageChange"
      />
    </el-card>

    <el-drawer
      v-loading="analyseDialogLoading"
      title="优化"
      :visible.sync="analyseDialogVisible"
      :destroy-on-close="true"
      :modal="true"
      size="80%"
      :modal-append-to-body="false"
    >
      <div style="padding: 0 30px;">
        <el-tabs v-model="analyseActionName" @tab-click="analyseActionHandleClick">
          <el-tab-pane label="根因分析" name="cause">
            <div ref="causeSuggestContainer" style="overflow: auto; height: 500px">

              <div
                v-for="(item, index) in sqlExplains"
                :key="index"
                class="sqlContainer"
                style="padding: 10px; margin-bottom: 10px; color:
                            #333333"
              >
                <span style="color: #666666">根因：</span>{{ item.nodeType }}<br><span style="color: #666666">执行代价：</span> {{ item.cost }}
              </div>

            </div>
          </el-tab-pane>
          <el-tab-pane label="索引建议" name="index">
            <div ref="indexSuggestContainer" style="overflow: auto; height: 500px">
              <div v-for="(item, index) in sqlIndexSelections" :key="index" class="indexSuggestSetp" style="overflow: auto; height: 500px">
                <div class="indexSuggestSetpTitle">
                  {{ `${index+1}. ${item.table_name}创建索引` }}
                </div>
                <div class="sqlContainer">
                  <div class="copyContainer">
                    <div class="copy-to-clipboard" @click="handleCopy(item.query)">
                      <el-tooltip class="item" effect="dark" content="复制SQL到剪贴板" placement="top-end">
                        <i class="el-icon-document-copy" />
                      </el-tooltip>
                    </div>
                  </div>
                  <highlightjs :code="sqlFormatter(item.query)" />
                </div>
              </div>
            </div>
          </el-tab-pane>
          <el-tab-pane label="计划建议" name="plan">
            <div ref="planSuggestContainer" style="overflow: auto; height: 500px" />
          </el-tab-pane>
          <el-tab-pane label="重写建议" name="rewrite">
            <div ref="rewriteSuggestContainer" style="overflow: auto; height: 500px">
              <div class="sqlContainer">
                <div class="copyContainer">
                  <div class="copy-to-clipboard" @click="handleRewriteCopy(analyseItem.query)">
                    <el-tooltip class="item" effect="dark" content="复制SQL到剪贴板" placement="top-end">
                      <i class="el-icon-document-copy" />
                    </el-tooltip>
                  </div>
                </div>
                <highlightjs :code="sqlFormatter(analyseItem.query ? analyseItem.query : '')" />
              </div>
            </div>
          </el-tab-pane>

        </el-tabs>
      </div>

    </el-drawer>

  </div>

</template>

<script>

import { format } from 'sql-formatter'
import { stringFoFixed2 } from '../../../utils/index'
import { sqlIndexSelection, sqlExplain, pgsqlSlowSqls, pgsqlServersSimpleInfo, pgsqlSlowSqlsCount, pgsqlSlowSqlsTimeDistribution } from '../../../api/api'
import moment from 'moment'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { LineChart, LinesChart, BarChart, PieChart } from 'echarts/charts'
import {
  GridComponent,
  PolarComponent,
  GeoComponent,
  TooltipComponent,
  LegendComponent,
  TitleComponent,
  VisualMapComponent,
  DatasetComponent,
  BrushComponent
} from 'echarts/components'
import { default as VChart, THEME_KEY } from 'vue-echarts'

use([
  CanvasRenderer,
  LineChart,
  BarChart,
  LinesChart,
  PieChart,
  GridComponent,
  PolarComponent,
  GeoComponent,
  TooltipComponent,
  LegendComponent,
  TitleComponent,
  VisualMapComponent,
  DatasetComponent,
  BrushComponent
])

export default {
  components: {
    VChart
  },
  provide: {
    [THEME_KEY]: 'light'
  },
  filters: {
    sqlFilter: function(value) {
      if (!value) {
        return ''
      }
      return value.length > 30 ? (value.slice(0, 30) + '...') : value
    }
  },
  data() {
    return {
      stringFoFixed2: stringFoFixed2,
      loading: false,
      sqlFormatter: format,
      dbSelecteds: [],
      keyParameter: [],
      dbSelectCondition: undefined,
      tableData: [],
      pageSize: 15,
      pageIndex: 1,
      totalItems: 0,
      analyseDialogVisible: false,
      analyseDialogLoading: false,
      analyseItem: {},
      analyseActionName: 'cause',
      sqlExplains: [],
      sqlIndexSelections: [],
      sqlQueryChartOption: {
        title: { show: false },
        grid: {
          left: 60,
          top: 50,
          bottom: 50,
          right: 30
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          }
        },
        color: ['#1890FF'],
        legend: {
          data: ['慢查询数'],
          top: 0,
          right: 10,
          icon: 'roundRect',
          align: 'left',
          textStyle: {
            fontSize: 10
          }
        },
        brush: {
          xAxisIndex: 'all',
          brushLink: 'all',
          outOfBrush: {
            colorAlpha: 0.3
          }
        },
        xAxis: {
          type: 'category',
          boundaryGap: false,
          nameTextStyle: {
            color: '#666666'
          },
          scale: true,
          axisLabel: {
            show: true,
            showMinLabel: true,
            fontSize: 10
          },
          axisLine: {
            show: true,
            lineStyle: {
              width: 0.5,
              color: '#999999',
              shadowColor: '#fff',
              shadowBlur: 10
            }
          },
          axisTick: {
            show: true,
            inside: true,
            length: 5,
            lineStyle: {
              width: 0.5,
              color: '#999999',
              shadowColor: '#fff',
              shadowBlur: 10
            }
          },
          data: []
        },
        yAxis: {
          type: 'value',
          offset: 0,
          nameTextStyle: {
            color: '#666666'
          },
          axisLabel: {
            show: true,
            showMinLabel: true,
            fontSize: 10,
            margin: 20
          },
          axisLine: {
            show: false
          },
          splitLine: {
            show: true,
            lineStyle: {
              color: '#e5e5e5',
              type: 'dotted'
            }
          },
          axisTick: {
            show: false
          }
        },
        series: [
          {
            name: '慢查询数',
            data: [],
            type: 'bar',
            smooth: true,
            showSymbol: false,
            hoverAnimation: true
          }
        ]
      },
      sqlSlowQueryChartOption: {
        title: { show: false },
        grid: {
          left: 50,
          top: 50,
          bottom: 50,
          right: 20
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          }
        },
        color: ['#F7CE85'],
        xAxis: {
          type: 'value',
          boundaryGap: false,
          axisLabel: {
            show: true,
            showMinLabel: true,
            fontSize: 10
          },
          axisLine: {
            show: true,
            lineStyle: {
              width: 0.5,
              color: '#999999',
              shadowColor: '#fff',
              shadowBlur: 10
            }
          },
          splitLine: {
            show: false,
            lineStyle: {
              color: '#e5e5e5',
              type: 'dotted'
            }
          },
          axisTick: {
            show: true,
            inside: true,
            length: 5,
            lineStyle: {
              width: 0.5,
              color: '#999999',
              shadowColor: '#fff',
              shadowBlur: 10
            }
          }
        },
        yAxis: {
          type: 'category',
          offset: 0,
          axisLabel: {
            show: true,
            showMinLabel: true,
            fontSize: 10
          },
          axisLine: {
            show: true,
            lineStyle: {
              width: 0.5,
              color: '#999999',
              shadowColor: '#fff',
              shadowBlur: 10
            }
          },
          splitLine: {
            show: true,
            lineStyle: {
              color: '#e5e5e5',
              type: 'dotted'
            }
          },
          axisTick: {
            show: false
          },
          data: []
        },
        series: [
          {
            name: '慢查询数',
            data: [],
            type: 'bar',
            barWidth: 20,
            smooth: true,
            showSymbol: false,
            hoverAnimation: true
          }
        ]
      },
      sqlQueryCoordRangeStart: '',
      sqlQueryCoordRangeEnd: '',
      dateSelectCondition: '',
      timeSelectCondition: ['', ''],
      start_time: '',
      end_time: ''
    }
  },
  watch: {
    sqlQueryCoordRangeStart: {
      handler: function(val, oldval) {
        this.getPgsqlSlowSqlsTimeDistribution()
        this.pageIndex = 1
        this.totalItems = 1
        this.getPgsqlSlowSqls()
      }
    },
    sqlQueryCoordRangeEnd: {
      handler: function(val, oldval) {
        this.getPgsqlSlowSqlsTimeDistribution()
        this.pageIndex = 1
        this.totalItems = 1
        this.getPgsqlSlowSqls()
      }
    }
  },
  mounted() {
    this.dateSelectCondition = moment().format('YYYY-MM-DD')
    this.timeSelectCondition = [moment().add(-1, 'hours').format('HH:mm:ss'), moment().format('HH:mm:ss')]
    this.getMysqlServersSimpleInfo()
    this.startActions()
  },
  methods: {
    getMysqlServersSimpleInfo() {
      pgsqlServersSimpleInfo({}).then((res) => {
        this.dbSelecteds = res.data
        this.dbSelectCondition = this.dbSelecteds[0].id
        this.selecteTime()
      }).catch(() => {
      })
    },
    getSqlExplain() {
      sqlExplain({ sql: this.analyseItem.query }).then((res) => {
        this.sqlExplains = res.data
      }).catch(() => {
      })
    },
    selecteTime() {
      this.start_time = `${this.dateSelectCondition} ${this.timeSelectCondition[0]}`
      this.end_time = `${this.dateSelectCondition} ${this.timeSelectCondition[1]}`

      this.getPgsqlSlowSqlsCount()
      this.getPgsqlSlowSqls()
      this.getPgsqlSlowSqlsTimeDistribution()
    },
    getPgsqlSlowSqlsCount() {
      this.loading = true
      pgsqlSlowSqlsCount({ server_id: this.dbSelectCondition, start_time: this.start_time, end_time: this.end_time }).then((res) => {
        this.loading = false
        const sqlTimeQuantumList = res.data
        // 实时SQL
        this.sqlQueryChartOption.xAxis.data = []
        this.sqlQueryChartOption.series[0].data = []
        for (let i = 0; i < sqlTimeQuantumList.length; i++) {
          this.sqlQueryChartOption.xAxis.data.push(moment(sqlTimeQuantumList[i]['time']).format('HH:mm:ss'))
          this.sqlQueryChartOption.series[0].data.push(sqlTimeQuantumList[i]['count'])
        }
        if (!this.sqlQueryCoordRangeStart) {
          this.sqlQueryCoordRangeStart = this.sqlQueryChartOption.xAxis.data[0]
        }
        if (!this.sqlQueryCoordRangeEnd) {
          this.sqlQueryCoordRangeEnd = this.sqlQueryChartOption.xAxis.data[1] ? this.sqlQueryChartOption.xAxis.data[1] : this.sqlQueryChartOption.xAxis.data[0]
        }
      }).catch(() => {
        this.loading = false
      })
    },
    getPgsqlSlowSqlsTimeDistribution() {
      this.loading = true

      const start_time = `${this.dateSelectCondition} ${this.sqlQueryCoordRangeStart}`
      const end_time = `${this.dateSelectCondition} ${this.sqlQueryCoordRangeEnd}`

      pgsqlSlowSqlsTimeDistribution({ server_id: this.dbSelectCondition, start_time: start_time, end_time: end_time }).then((res) => {
        this.loading = false
        const sqlTimeDistributionList = res.data
        // 实时SQL
        this.sqlSlowQueryChartOption.yAxis.data = []
        this.sqlSlowQueryChartOption.series[0].data = []
        for (let i = 0; i < sqlTimeDistributionList.length; i++) {
          this.sqlSlowQueryChartOption.yAxis.data.push(sqlTimeDistributionList[i]['time'])
          this.sqlSlowQueryChartOption.series[0].data.push(sqlTimeDistributionList[i]['count'])
        }
      }).catch(() => {
        this.loading = false
      })
    },
    getSqlIndexSelection() {
      sqlIndexSelection({ workload: JSON.stringify([this.analyseItem.query]) }).then((res) => {
        if (res.code === 0) {
          this.sqlIndexSelections = res.result_list
          if (this.sqlIndexSelections.length === 0) {
            this.$message.success('该语句未获取到索引建议，可检查是否已经添加过索引')
          }
        } else {
          this.$message.error('获取索引建议失败，请检测语句是否正确')
        }
      })
    },
    getPgsqlSlowSqls() {
      this.loading = true
      const start_time = `${this.dateSelectCondition} ${this.sqlQueryCoordRangeStart}`
      const end_time = `${this.dateSelectCondition} ${this.sqlQueryCoordRangeEnd}`
      pgsqlSlowSqls({
        server_id: this.dbSelectCondition, page: this.pageIndex, page_size: this.pageSize, start_time: start_time, end_time: end_time }).then((res) => {
        this.loading = false
        this.tableData = res.data.data
        this.totalItems = res.data.count
        console.log(this.tableData)
      }).catch(() => {
        this.loading = false
      })
    },
    analyse(item) {
      this.analyseItem = JSON.parse(JSON.stringify(item))
      this.analyseDialogVisible = true
      this.getSqlExplain()
      this.getSqlIndexSelection()
    },
    handleRewriteCopy(value) {
      const that = this
      this.$copyText(value).then(function(e) {
        that.$message.success(' 已复制到剪贴板！')
        console.log(e)
      }, function(e) {
        that.$message.error('复制失败，请使用Ctrl+C复制')
        console.log(e)
      })
    },
    handleCopy(value) {
      const that = this
      this.$copyText(value).then(function(e) {
        that.$message.success(' 已复制到剪贴板！')
        console.log(e)
      }, function(e) {
        that.$message.error('复制失败，请使用Ctrl+C复制')
        console.log(e)
      })
    },
    analyseActionHandleClick(tab) {
      switch (tab.name) {
        case 'cause':
          this.$refs['causeSuggestContainer'].style.height = Math.max(window.innerHeight - 450, 100) + 'px'
          break
        case 'index':
          this.$refs['indexSuggestContainer'].style.height = Math.max(window.innerHeight - 450, 100) + 'px'
          break
        case 'plan':
          this.$refs['planSuggestContainer'].style.height = Math.max(window.innerHeight - 450, 100) + 'px'
          break
        case 'rewrite':
          this.$refs['rewriteSuggestContainer'].style.height = Math.max(window.innerHeight - 450, 100) + 'px'
          break
        default:
          break
      }
    },
    async curPageChange(page) {
      this.pageIndex = page
      this.getPgsqlSlowSqls()
    },
    brushEnd(params) {
      this.sqlQueryCoordRangeStart = this.sqlQueryChartOption.xAxis.data[params.areas[0].coordRange[0] < 0 ? 0 : params.areas[0].coordRange[0]]
      this.sqlQueryCoordRangeEnd = this.sqlQueryChartOption.xAxis.data[params.areas[0].coordRange[1] >= this.sqlQueryChartOption.xAxis.data.length
        ? this.sqlQueryChartOption.xAxis.data.length - 1
        : params.areas[0].coordRange[1]]
    },
    startActions() {
      const sqlQueryChart = this.$refs.sqlQueryChart
      if (!sqlQueryChart) {
        return
      }
      sqlQueryChart.dispatchAction({
        type: 'brush',
        areas: [
          {
            brushType: 'lineX',
            coordRange: [0, 10],
            xAxisIndex: 0
          }
        ]
      })
    }
  }
}

</script>

<style lang="scss" scoped>

  @import "../../../styles/vue-hljs-theme.css";
  @import "../../../styles/table.css";

  .container {
    display: flex;
    flex-direction: column;
    width: 100%;
  }

  .top-card-title {
    color: rgba(0, 0, 0, 0.45);
    font-size: 14px;
    line-height: 22px;
  }

  .top-card-detail {
    color: rgba(0, 0, 0, 0.85);
    font-weight: bolder;
    white-space: nowrap;
    word-break: break-all;
    font-size: 30px;
    line-height: 60px;
  }

  .card-header-title {
    color: rgba(0, 0, 0, 0.85);
    font-weight: 500;
    white-space: nowrap;
    word-break: break-all;
    font-size: 18px;
  }

  .el-divider--horizontal {
    margin: 20px 0;
  }

  .el-col-5 {
    width: 20%;
  }

  .table_container {
    overflow: auto;
  }

  .table_btns_container {
    display: flex;
    flex-direction: row;
    align-content: space-around;
    height: 30px;
    line-height: 30px;
    margin: 10px auto;
    width: 100%;
  }

  .table_btns_item_container {
    flex: 0 0 33.333%;
    display: flex;
    justify-content: center;
  }

  .healthChart {
    width: 100%;
    height: 260px;
  }

  .sqlQueryChart {
    width: 100%;
    height: 300px;
  }

  .sqlSlowQueryChart {
    width: 100%;
    height: 300px;
  }

  .report-list-container {
    height: 190px;
    width: 100%;
    overflow: auto;
  }

  .report-list-item {
    width: 100%;
    height: 40px;
    line-height: 40px;
    display: flex;
    color: rgba(0, 0, 0, 0.65);
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
  }

  .dialogSectionHeaderTitle {
    font-size: 16px;
    color: #333333;
    font-weight: bold;
    margin-bottom: 20px;
  }

  .sqlContainer {
    width: 80%;
    background: #f5f5f5;
    border-radius: 4px;
    white-space: pre;
    padding: 0 10px;
    color: #000000;
    font-size: 1em;
    position: relative;
    text-align: left;
  }

  .copyContainer {
    position: absolute;
    right: 6px;
    top: 6px;
  }

  .el-icon-document-copy:hover {
    color: #409EFF;
  }

  .el-icon-document-copy:active {
    color: #000000;
  }

  .dialogSqlSlowQueryChart {
    width: 100%;
    height: 150px;
  }

  .ipChart {
    width: 100%;
    height: 200px;
  }

  .el-drawer:focus {
    outline: none;
  }

  .indexSuggestSetp {
    margin-top: 10px;
  }

  .indexSuggestSetpTitle {
    color: #666666;
    font-size: 10px;
    line-height: 30px;
  }

</style>

